/**
 * Copyright (c) 2009, Robert Schuster
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the
 * following conditions are met:
 *
 * - Redistributions of source code must retain the above
 *   copyright notice, this list of conditions and the
 *   following disclaimer.
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the
 *   following disclaimer in the documentation and/or other
 *   materials provided with the distribution.
 * - Neither the name of Robert Schuster nor the names of his
 *   contributors may be used to endorse or promote products
 *   derived from this software without specific prior written
 *   permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* 
 * File:   Environment.cpp
 * Author: robert
 * 
 * Created on 31. August 2009, 15:10
 */

#include "Environment.hpp"

//all functions are defined inside the namespace CLcalc
namespace CLcalc {

Environment::Environment() throw (Error) {
    cl_uint num_devices;
    /*
     * Array with all CL-Devices
     */
    cl_device_id compute_device_id[10];

    int err = clGetDeviceIDs(NULL,CL_DEVICE_TYPE_ALL, 10, &compute_device_id[0], &num_devices);
    
    //loop over all devices, sort them by Device-Type
    for (int i=0;i<num_devices;i++) {
        size_t typ;
        err |= clGetDeviceInfo(compute_device_id[i], CL_DEVICE_TYPE, sizeof(typ), &typ, NULL);

        Device* device = new Device(compute_device_id[i]);
        if (typ == CL_DEVICE_TYPE_GPU) {
            GPUs.push_back(device);
        }
        if (typ == CL_DEVICE_TYPE_CPU) {
            CPUs.push_back(device);
        }
    }

}

Environment::~Environment() {
    //cout << "~Environment()" << endl;
    CPUs.clear();
    GPUs.clear();
    Execs.clear();
    //cout << "~Environment()" << endl;
}

Device* Environment::getDevice(int device_typ) {
    Device* ergebnis = NULL;

    //get the device id
    switch (device_typ) {
        case CLcalc_DEVICE_cpu0:
            if (CPUs.size() > 0) ergebnis = &CPUs[0];
            break;
        case CLcalc_DEVICE_cpu1:
            if (CPUs.size() > 1) ergebnis = &CPUs[1];
            break;
        case CLcalc_DEVICE_gpu0:
            if (GPUs.size() > 0) ergebnis = &GPUs[0];
            break;
        case CLcalc_DEVICE_gpu1:
            if (GPUs.size() > 1) ergebnis = &GPUs[1];
            break;
    }
    //cout << "getDevice: " << ergebnis->getDeviceName() << endl;
    return ergebnis;

}

int Environment::createExecutor(int device_type) throw (Error) {
    Device* device = getDevice(device_type);

    //is there a valid Device?
    if (device == NULL) {
        throw Error(-1);
    }

    //Create a new Executor for this Device
    Executor* ex = new Executor(device);

    //Add the Executor to the Vector
    Execs.push_back(ex);

    //Return the Index in the Vector as ID
    return Execs.size()-1;
}

Executor* Environment::getExecutor(int ExecutorID) throw (Error) {
    //A Valid ID?
    if (Execs.size() <= ExecutorID) throw Error(-1);

    //return the pointer
    return &Execs[ExecutorID];
}

void Environment::shutdownExecutor(int ExecutorID) throw (Error) {
    //A Valid ID?
    if (Execs.size() <= ExecutorID) throw Error(-1);

    //replace this Executor with NULL too keep the other IDs valid
    Execs.replace(ExecutorID, NULL);
}

}// end of namespace CLclac